home *** CD-ROM | disk | FTP | other *** search
- //------------------------------------------------------------------------------
- // File: PlayCap.cpp
- //
- // Desc: DirectShow sample code - a very basic application using Capture
- // Devices. It creates a window and uses the first available Capture
- // Device to render and preview video capture data.
- //
- // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
-
-
- #include <atlbase.h>
- #include <windows.h>
- #include <dshow.h>
- #include <stdio.h>
-
- #include "playcap.h"
-
- // An application can advertise the existence of its filter graph
- // by registering the graph with a global Running Object Table (ROT).
- // The GraphEdit application can detect and remotely view the running
- // filter graph, allowing you to 'spy' on the graph with GraphEdit.
- //
- // To enable registration in this sample, define REGISTER_FILTERGRAPH.
- //
- #define REGISTER_FILTERGRAPH
-
-
- //
- // Global data
- //
- HWND ghApp=0;
- DWORD g_dwGraphRegister=0;
-
- IVideoWindow * g_pVW = NULL;
- IMediaControl * g_pMC = NULL;
- IMediaEventEx * g_pME = NULL;
- IGraphBuilder * g_pGraph = NULL;
- ICaptureGraphBuilder2 * g_pCapture = NULL;
- PLAYSTATE g_psCurrent = Stopped;
-
-
- HRESULT CaptureVideo()
- {
- HRESULT hr;
- IBaseFilter *pSrcFilter=NULL;
-
- // Get DirectShow interfaces
- hr = GetInterfaces();
- if (FAILED(hr))
- {
- Msg(TEXT("Failed to get video interfaces! hr=0x%x"), hr);
- return hr;
- }
-
- // Attach the filter graph to the capture graph
- hr = g_pCapture->SetFiltergraph(g_pGraph);
- if (FAILED(hr))
- {
- Msg(TEXT("Failed to set capture filter graph! hr=0x%x"), hr);
- return hr;
- }
-
- // Use the system device enumerator and class enumerator to find
- // a video capture/preview device, such as a desktop USB video camera.
- hr = FindCaptureDevice(&pSrcFilter);
- if (FAILED(hr))
- {
- // Don't display a message because FindCaptureDevice will handle it
- return hr;
- }
-
- // Add Capture filter to our graph.
- hr = g_pGraph->AddFilter(pSrcFilter, L"Video Capture");
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't add capture filter to graph! hr=0x%x"), hr);
- pSrcFilter->Release();
- return hr;
- }
-
- // Render the preview pin on the video capture filter
- // Use this instead of g_pGraph->RenderFile
- hr = g_pCapture->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
- pSrcFilter, NULL, NULL);
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't render capture stream. ")
- TEXT("The device may already be in use.\r\n\r\nhr=0x%x"), hr);
- pSrcFilter->Release();
- return hr;
- }
-
- // Now that the filter has been added to the graph and we have
- // rendered its stream, we can release this reference to the filter.
- pSrcFilter->Release();
-
- // Set video window style and position
- hr = SetupVideoWindow();
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't initialize video window! hr=0x%x"), hr);
- return hr;
- }
-
- // Add our graph to the running object table, which will allow
- // the GraphEdit application to "spy" on our graph
- #ifdef REGISTER_FILTERGRAPH
- hr = AddGraphToRot(g_pGraph, &g_dwGraphRegister);
- if (FAILED(hr))
- {
- Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr);
- g_dwGraphRegister = 0;
- }
- #endif
-
- // Start previewing video data
- hr = g_pMC->Run();
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't run the graph! hr=0x%x"), hr);
- return hr;
- }
-
- // Remember current state
- g_psCurrent = Running;
-
- return S_OK;
- }
-
-
- HRESULT FindCaptureDevice(IBaseFilter ** ppSrcFilter)
- {
- HRESULT hr;
- IBaseFilter * pSrc = NULL;
- CComPtr <IMoniker> pMoniker =NULL;
- ULONG cFetched;
-
- // Create the system device enumerator
- CComPtr <ICreateDevEnum> pDevEnum =NULL;
-
- hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
- IID_ICreateDevEnum, (void ** ) &pDevEnum);
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't create system enumerator! hr=0x%x"), hr);
- return hr;
- }
-
- // Create an enumerator for the video capture devices
- CComPtr <IEnumMoniker> pClassEnum = NULL;
-
- hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't create class enumerator! hr=0x%x"), hr);
- return hr;
- }
-
- // If there are no enumerators for the requested type, then
- // CreateClassEnumerator will succeed, but pClassEnum will be NULL.
- if (pClassEnum == NULL)
- {
- MessageBox(ghApp,TEXT("No video capture device was detected.\r\n\r\n")
- TEXT("This sample requires a video capture device, such as a USB WebCam,\r\n")
- TEXT("to be installed and working properly. The sample will now close."),
- TEXT("No Video Capture Hardware"), MB_OK | MB_ICONINFORMATION);
- return E_FAIL;
- }
-
- // Use the first video capture device on the device list.
- // Note that if the Next() call succeeds but there are no monikers,
- // it will return S_FALSE (which is not a failure). Therefore, we
- // check that the return code is S_OK instead of using SUCCEEDED() macro.
- if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
- {
- // Bind Moniker to a filter object
- hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
- if (FAILED(hr))
- {
- Msg(TEXT("Couldn't bind moniker to filter object! hr=0x%x"), hr);
- return hr;
- }
- }
- else
- {
- Msg(TEXT("Unable to access video capture device!"));
- return E_FAIL;
- }
-
- // Copy the found filter pointer to the output parameter.
- // Do NOT Release() the reference, since it will still be used
- // by the calling function.
- *ppSrcFilter = pSrc;
-
- return hr;
- }
-
-
- HRESULT GetInterfaces(void)
- {
- HRESULT hr;
-
- // Create the filter graph
- hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
- IID_IGraphBuilder, (void **) &g_pGraph);
- if (FAILED(hr))
- return hr;
-
- // Create the capture graph builder
- hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
- IID_ICaptureGraphBuilder2, (void **) &g_pCapture);
- if (FAILED(hr))
- return hr;
-
- // Obtain interfaces for media control and Video Window
- hr = g_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &g_pMC);
- if (FAILED(hr))
- return hr;
-
- hr = g_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *) &g_pVW);
- if (FAILED(hr))
- return hr;
-
- hr = g_pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *) &g_pME);
- if (FAILED(hr))
- return hr;
-
- // Set the window handle used to process graph events
- hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);
-
- return hr;
- }
-
-
- void CloseInterfaces(void)
- {
- // Stop previewing data
- if (g_pMC)
- g_pMC->StopWhenReady();
-
- g_psCurrent = Stopped;
-
- // Stop receiving events
- if (g_pME)
- g_pME->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0);
-
- // Relinquish ownership (IMPORTANT!) of the video window.
- // Failing to call put_Owner can lead to assert failures within
- // the video renderer, as it still assumes that it has a valid
- // parent window.
- if(g_pVW)
- {
- g_pVW->put_Visible(OAFALSE);
- g_pVW->put_Owner(NULL);
- }
-
- #ifdef REGISTER_FILTERGRAPH
- // Remove filter graph from the running object table
- if (g_dwGraphRegister)
- RemoveGraphFromRot(g_dwGraphRegister);
- #endif
-
- // Release DirectShow interfaces
- SAFE_RELEASE(g_pMC);
- SAFE_RELEASE(g_pME);
- SAFE_RELEASE(g_pVW);
- SAFE_RELEASE(g_pGraph);
- SAFE_RELEASE(g_pCapture);
- }
-
-
- HRESULT SetupVideoWindow(void)
- {
- HRESULT hr;
-
- // Set the video window to be a child of the main window
- hr = g_pVW->put_Owner((OAHWND)ghApp);
- if (FAILED(hr))
- return hr;
-
- // Set video window style
- hr = g_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
- if (FAILED(hr))
- return hr;
-
- // Use helper function to position video window in client rect
- // of main application window
- ResizeVideoWindow();
-
- // Make the video window visible, now that it is properly positioned
- hr = g_pVW->put_Visible(OATRUE);
- if (FAILED(hr))
- return hr;
-
- return hr;
- }
-
-
- void ResizeVideoWindow(void)
- {
- RECT rc;
-
- // Make the preview video fill our window
- GetClientRect(ghApp, &rc);
-
- // Resize the video preview window to match owner window size
- if (g_pVW)
- g_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);
- }
-
-
- HRESULT ChangePreviewState(int nShow)
- {
- HRESULT hr=S_OK;
-
- // If the media control interface isn't ready, don't call it
- if (!g_pMC)
- return S_OK;
-
- if (nShow)
- {
- if (g_psCurrent != Running)
- {
- // Start previewing video data
- hr = g_pMC->Run();
- g_psCurrent = Running;
- }
- }
- else
- {
- // Stop previewing video data
- hr = g_pMC->StopWhenReady();
- g_psCurrent = Stopped;
- }
-
- return hr;
- }
-
-
- #ifdef REGISTER_FILTERGRAPH
-
- HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
- {
- IMoniker * pMoniker;
- IRunningObjectTable *pROT;
- WCHAR wsz[128];
- HRESULT hr;
-
- if (FAILED(GetRunningObjectTable(0, &pROT))) {
- return E_FAIL;
- }
-
- wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph,
- GetCurrentProcessId());
-
- hr = CreateItemMoniker(L"!", wsz, &pMoniker);
- if (SUCCEEDED(hr)) {
- hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
- pMoniker->Release();
- }
- pROT->Release();
- return hr;
- }
-
-
- void RemoveGraphFromRot(DWORD pdwRegister)
- {
- IRunningObjectTable *pROT;
-
- if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
- pROT->Revoke(pdwRegister);
- pROT->Release();
- }
- }
-
- #endif
-
-
- void Msg(TCHAR *szFormat, ...)
- {
- TCHAR szBuffer[512];
-
- va_list pArgs;
- va_start(pArgs, szFormat);
- _vstprintf(szBuffer, szFormat, pArgs);
- va_end(pArgs);
-
- MessageBox(NULL, szBuffer, TEXT("PlayCap Message"), MB_OK | MB_ICONERROR);
- }
-
-
- HRESULT HandleGraphEvent(void)
- {
- LONG evCode, evParam1, evParam2;
- HRESULT hr=S_OK;
-
- while(SUCCEEDED(g_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
- (LONG_PTR *) &evParam2, 0)))
- {
- //
- // Free event parameters to prevent memory leaks associated with
- // event parameter data. While this application is not interested
- // in the received events, applications should always process them.
- //
- hr = g_pME->FreeEventParams(evCode, evParam1, evParam2);
-
- // Insert event processing code here, if desired
- }
-
- return hr;
- }
-
-
- LRESULT CALLBACK WndMainProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- switch (message)
- {
- case WM_GRAPHNOTIFY:
- HandleGraphEvent();
- break;
-
- case WM_SIZE:
- ResizeVideoWindow();
- break;
-
- case WM_WINDOWPOSCHANGED:
- ChangePreviewState(! (IsIconic(hwnd)));
- break;
-
- case WM_CLOSE:
- // Hide the main window while the graph is destroyed
- ShowWindow(ghApp, SW_HIDE);
- CloseInterfaces(); // Stop capturing and release interfaces
- break;
-
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc (hwnd , message, wParam, lParam);
- }
-
-
- int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hInstP, LPSTR lpCmdLine, int nCmdShow)
- {
- MSG msg={0};
- WNDCLASS wc;
-
- // Initialize COM
- if(FAILED(CoInitialize(NULL)))
- {
- Msg(TEXT("CoInitialize Failed!\r\n"));
- exit(1);
- }
-
- // Register the window class
- ZeroMemory(&wc, sizeof wc);
- wc.lpfnWndProc = WndMainProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASSNAME;
- wc.lpszMenuName = NULL;
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_VIDPREVIEW));
- if(!RegisterClass(&wc))
- {
- Msg(TEXT("RegisterClass Failed! Error=0x%x\r\n"), GetLastError());
- CoUninitialize();
- exit(1);
- }
-
- // Create the main window. The WS_CLIPCHILDREN style is required.
- ghApp = CreateWindow(CLASSNAME, APPLICATIONNAME,
- WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_CLIPCHILDREN,
- CW_USEDEFAULT, CW_USEDEFAULT,
- DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT,
- 0, 0, hInstance, 0);
-
- if(ghApp)
- {
- HRESULT hr;
-
- // Create DirectShow graph and start capturing video
- hr = CaptureVideo();
- if (FAILED (hr))
- {
- CloseInterfaces();
- DestroyWindow(ghApp);
- }
- else
- {
- // Don't display the main window until the DirectShow
- // preview graph has been created. Once video data is
- // being received and processed, the window will appear
- // and immediately have useful video data to dispay.
- // Otherwise, it will be black until video data arrives.
- ShowWindow(ghApp, nCmdShow);
- }
-
- // Main message loop
- while(GetMessage(&msg,NULL,0,0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
-
- // Release COM
- CoUninitialize();
-
- return (int) msg.wParam;
- }
-